package com.eelye.util.http.impl;

import com.eelye.util.http.EasyHttpClient;
import com.eelye.util.http.enums.RequestMethodEnum;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.NotImplementedException;

import java.io.IOException;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用okhttp实现的httpclient，所以名字有两个http。
 */
@Slf4j
public class OkHttpHttpClient implements EasyHttpClient {

    public static final int CONNECT_TIME_OUT = 1000;
    public static final int REQUEST_TIME_OUT = 30_000;

    OkHttpClient m_client;

    Proxy proxy;
    ProxySelector proxySelector = new ProxySelector() {

        @Override
        public List<Proxy> select(URI uri) {
            if (null == proxy) {
                return new ArrayList<>();
            }

            return Collections.singletonList(proxy);
        }

        @Override
        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {

        }
    };

    public OkHttpHttpClient() {
        m_client = new OkHttpClient().newBuilder()
                .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)
                .callTimeout(REQUEST_TIME_OUT, TimeUnit.MILLISECONDS)
                .proxySelector(proxySelector)
                .build();
    }

    @Override
    public void setProxy(String ip, int port) {
        if ("".equals(ip) && 0 == port) {
            proxy = null;
        } else {
            SocketAddress sa = new InetSocketAddress(ip, port);
            proxy = new Proxy(Proxy.Type.HTTP, sa);
        }
    }

    @Override
    public <T> T request(RequestMethodEnum method, String uri, String data, Map<String, String> headers, Class<T> t)
            throws IOException {
        Request.Builder reqBuilder = new Request.Builder()
                .url(uri);
        switch (method) {
            case Get:
                reqBuilder.get();
                break;
            case Post:
                MediaType mediaTypeJson = MediaType.parse("application/json;charset=utf-8");
                reqBuilder.post(RequestBody.create(data, mediaTypeJson));
                break;
            default:
                throw new NotImplementedException();
        }

        if (null != headers) {
            for (Map.Entry<String, String> e : headers.entrySet()) {
                reqBuilder.addHeader(e.getKey(), e.getValue());
            }
        }
        Request req = reqBuilder.build();

        Response resp = m_client.newCall(req).execute();
        if (String.class.equals(t)) {
            ResponseBody body = resp.body();
            MediaType contentType = body.contentType();
            Charset charset = null == contentType ? StandardCharsets.UTF_8 : body.contentType().charset();
            if (null == charset) {
                charset = StandardCharsets.UTF_8;
            }
            byte[] bytes = body.bytes();
            String ret = new String(bytes, charset);
            return (T) ret;
        }

        return (T) resp;
    }

    @Override
    public void close() {
        m_client.connectionPool().evictAll();
    }
}
